import React, { useState, useEffect, useRef } from 'react';
import sparkMd5 from 'spark-md5';
export default function File() {
    const FileHash = useRef('')
    const FileName = useRef('')
    const CHUNK_SIZE = 1024 * 1024  //1MB
    const createChunks = (file) => {
        let cur = 0
        let chunks = []
        while (cur < file.size) {
            const blod = file.slice(cur, cur + CHUNK_SIZE)
            chunks.push(blod)
            cur += CHUNK_SIZE
        }
        return chunks
    }
    const calculateHash = (chunks) => {
        return new Promise(resolve => {
            const targets = []
            const spark = new sparkMd5.ArrayBuffer()  //创建一个sparkMd5对象
            const fileReader = new FileReader()  //创建一个FileReader对象
            chunks.forEach((chunk, index) => {
                if (index == 0 || index == chunks.length - 1) {
                    targets.push(chunk)
                } else {
                    targets.push(chunk.slice(0, 2))
                    targets.push(chunk.slice(CHUNK_SIZE / 2, CHUNK_SIZE / 2 + 2))
                    targets.push(chunk.slice(CHUNK_SIZE - 2, CHUNK_SIZE + 1))
                }
            })
            fileReader.readAsArrayBuffer(new Blob(targets))  //将文件读取为ArrayBuffer,并将结果存储在fileReader.result中
            fileReader.onload = (e) => {  //当文件读取完成时触发
                spark.append(e.target.result)  //将ArrayBuffer添加到sparkMd5对象中
                // console.log(spark.end())  //计算sparkMd5对象的hash值
                resolve(spark.end())
            }
        })

    }
    const mergeRequest = async () => {
        fetch("http://localhost:3500/merge", {
            method: 'POST',
            headers: { "content-type": "application/json" },
            body: JSON.stringify({
                FileHash: FileHash.current,
                FileName: FileName.current,
                size: CHUNK_SIZE
            })
        }).then(res => {
            alert("合并成功")
        })
    }
    const uploadChunks = async (chunks,existChunks) => {
        const data = chunks.map((chunk, index) => {
            return {
                FileHash: FileHash.current,
                chunkHash: FileHash.current + "_" + index,
                chunk
            }
        })
        const formDatas = data.filter((item)=>!existChunks.includes(item.chunkHash)).map((item) => {
            const formData = new FormData()
            formData.append('FileHash', item.FileHash)
            formData.append('chunkHash', item.chunkHash)
            formData.append('chunk', item.chunk)
            return formData
        }) //将文件转换为FormData对象
        // console.log(formDatas)
        const max = 6 //最大并发数
        let i = 0
        const taskPool = [] //任务池
        while (i < formDatas.length) {
            const task = fetch("http://localhost:3500/upload", {
                method: 'POST',
                body: formDatas[i]
            })
            taskPool.push(task)
            if (taskPool.length == max) {
                await Promise.race(taskPool).then(completedTask => {
                    const index = taskPool.indexOf(completedTask)
                    if (index != -1) {
                        taskPool.splice(index, 1)
                    }
                })
            }
            i++
        }
        await Promise.all(taskPool)
        // 通知后端合并文件
        mergeRequest()
    }
    const verify = () => {
        return fetch("http://localhost:3500/verify", {
            method: 'POST',
            headers: { "content-type": "application/json" },
            body: JSON.stringify({
                FileHash: FileHash.current,
                FileName: FileName.current,
            })
        })
            .then(res => res.json())
            .then(res => {
                return res
            })
    }
    const handle = async (e) => {
        const files = e.target.files
        if (!files) return
        FileName.current = files[0].name
        const chunks = createChunks(files[0])
        const hash = await calculateHash(chunks)
        FileHash.current = hash //将hash值存储在fileHash中
        const data=await verify()
        if(data.data.shouldUpload==false){
            alert("文件已存在")
            return
        }
        uploadChunks(chunks,data.data.existChunks)
    }
    return (
        <div>
            <h1>大文件上传</h1>
            <input type="file" onChange={(e) => handle(e)} />
        </div>
    )
}